#include <fstream>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "json.hpp"
#include "ThostFtdcTraderApi.h"
#include "TdSpi.h"
#include "Timer.hpp"
#define CTPCON "./"
using namespace std;

pthread_cond_t doneCond; 
pthread_mutex_t doneMutex; 

extern pthread_cond_t doneCond; 
extern pthread_mutex_t doneMutex; 

int main(int argc, char *argv[], char **env)
{
	std::string USER="user.json";
	if(argc>1)
		USER=argv[1];
	ifstream in;
	in.open(USER.c_str());
    string content((istreambuf_iterator<char>(in)), istreambuf_iterator<char>());
	in.close();
	nlohmann::json config = nlohmann::json::parse(content);
	char TD_FRONT[64],BROKER_ID[64],INVESTOR_ID[64],PASSWORD[64],APPID[64],AUTHCODE[64];
	strcpy(TD_FRONT, config["TD_FRONT"].get<string>().c_str());
	strcpy(INVESTOR_ID, config["INVESTOR_ID"].get<string>().c_str());
	strcpy(BROKER_ID, config["BROKER_ID"].get<string>().c_str());
	strcpy(PASSWORD,  config["PASSWORD"].get<string>().c_str());
	strcpy(APPID,     config["APPID"].get<string>().c_str());
	strcpy(AUTHCODE,  config["AUTHCODE"].get<string>().c_str());

	int ptr = 0;
	const char* fn = config["TRADE_RECORD"].get<string>().c_str();
	int ft = open(fn,O_RDWR);
	Order order;
	if(ft == -1)
	{
		memset(&order,0,sizeof(Order));
		int fw=open(fn, O_WRONLY|O_CREAT|O_TRUNC,00644);
		for(long i=0;i<OrderCapacity; i++)
			int r=write(fw,&order,sizeof(Order));
		close(fw);
		fprintf(stderr,"create %s, size: %ldMB\n",fn, sizeof(Order)*OrderCapacity/1024/1024);
		ft = open(fn,O_RDWR);
	}

	Order* orders = (Order*)mmap(NULL,sizeof(Order)*OrderCapacity, PROT_READ|PROT_WRITE,MAP_SHARED, ft, 0);
	close(ft);
	while((orders + ptr)->sent_nano > 0)
	{
		ptr++;
	}
	fprintf(stderr,"start from trade ptr:%d\n",ptr);

	TdSpi* tradeSpi=new TdSpi();

	CThostFtdcTraderApi* tradeAPI = CThostFtdcTraderApi::CreateFtdcTraderApi(CTPCON);	
	tradeAPI->RegisterSpi(tradeSpi);
	tradeAPI->RegisterFront(TD_FRONT);
	tradeAPI->SubscribePublicTopic(THOST_TERT_QUICK);
	tradeAPI->SubscribePrivateTopic(THOST_TERT_QUICK);
	pthread_mutex_lock(&doneMutex);	
	tradeAPI->Init();
	fprintf(stderr,"connecting to trading front %s ",TD_FRONT);
	pthread_cond_wait (&doneCond, &doneMutex); 
	pthread_mutex_unlock (&doneMutex); 
	fprintf(stderr,"Connected\n");

	int iRequestID=0,result=0;
	// Authorize 
	CThostFtdcReqAuthenticateField authField;
	memset(&authField, 0, sizeof(authField));
	strcpy(authField.BrokerID, BROKER_ID);
	strcpy(authField.UserID,   INVESTOR_ID);
	strcpy(authField.AppID,    APPID);
	strcpy(authField.AuthCode, AUTHCODE);
	pthread_mutex_lock(&doneMutex);
	tradeAPI->ReqAuthenticate(&authField, ++iRequestID);
	pthread_cond_wait (&doneCond, &doneMutex); 
	pthread_mutex_unlock (&doneMutex); 

	// Login 
	CThostFtdcReqUserLoginField req;
	memset(&req, 0, sizeof(req));
	strcpy(req.BrokerID, BROKER_ID);
	strcpy(req.UserID,   INVESTOR_ID);
	strcpy(req.Password, PASSWORD);
	pthread_mutex_lock(&doneMutex);
	tradeAPI->ReqUserLogin(&req, ++iRequestID);	
	pthread_cond_wait (&doneCond, &doneMutex); 
	pthread_mutex_unlock (&doneMutex); 
	// Confirm SettlementInfo 
	CThostFtdcSettlementInfoConfirmField req1;
	memset(&req1, 0, sizeof(req1));
	strcpy(req1.BrokerID, BROKER_ID);
	strcpy(req1.InvestorID, INVESTOR_ID);
	pthread_mutex_lock(&doneMutex);
	result=tradeAPI->ReqSettlementInfoConfirm(&req1, ++iRequestID);
	pthread_cond_wait (&doneCond, &doneMutex); 
	pthread_mutex_unlock (&doneMutex); 

	// fetch positions 
	CThostFtdcQryInvestorPositionDetailField req2;
	memset(&req2, 0, sizeof(req2));
	strcpy(req2.BrokerID, BROKER_ID);
	strcpy(req2.InvestorID, INVESTOR_ID);			
	pthread_mutex_lock(&doneMutex);
	tradeAPI->ReqQryInvestorPositionDetail(&req2, ++iRequestID);
	pthread_cond_wait (&doneCond, &doneMutex); 
	pthread_mutex_unlock (&doneMutex);

	fprintf(stderr,"start\n");
	while(1)
	{
		// read order
		Order* order = orders + ptr;
		if(order->order_nano > 0)
		{
			char offset = THOST_FTDC_OF_Open;
			if(order->offset == 'C')
				offset = tradeSpi->checkPosition(order->symbol);
			CThostFtdcInputOrderField req;
			memset(&req, 0, sizeof(req));
			req.OrderPriceType = THOST_FTDC_OPT_LimitPrice;
			req.CombHedgeFlag[0] = THOST_FTDC_HF_Speculation;	
			req.TimeCondition = THOST_FTDC_TC_GFD;///有效期类型: 当日有效	
			req.VolumeCondition = THOST_FTDC_VC_AV;///成交量类型: 任何数量	
			req.MinVolume = 1;///最小成交量: 1	
			req.ContingentCondition = THOST_FTDC_CC_Immediately;///触发条件: 立即	
			req.ForceCloseReason = THOST_FTDC_FCC_NotForceClose;///强平原因: 非强	
			req.IsAutoSuspend = 1;///自动挂起标志: 是	
			req.UserForceClose = 0;///用户强评标志: 否
			strcpy(req.OrderRef , to_string(order->id).c_str());
			strcpy(req.BrokerID, BROKER_ID);
			strcpy(req.InvestorID, INVESTOR_ID);
			strcpy(req.InstrumentID, order->symbol);
			req.Direction = order->direction =='B'? THOST_FTDC_D_Buy : THOST_FTDC_D_Sell;
			req.CombOffsetFlag[0] = offset;
			req.LimitPrice = order->entrust_price;
			req.VolumeTotalOriginal = order->target_volume;

			tradeSpi->setTarget(order);				

			pthread_mutex_lock(&doneMutex);
			tradeAPI->ReqOrderInsert(&req, ++iRequestID);
			pthread_cond_wait (&doneCond, &doneMutex); 
			pthread_mutex_unlock (&doneMutex);
			memcpy(order, tradeSpi->getTarget(), sizeof(Order));
			ptr += 1;
		}
		if(tradeSpi->isClosed())
			break;
	}
	fprintf(stderr,"market close\n");
	return 0;
}
